package org.googlecode.lightning.search.index;

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class IndexWriterFactory {
	public static final int INDEX_MERGE_FACTOR_DEFAULT = 128;
	public static final double INDEX_RAM_BUFFER_SIZE_DEFAULT = 64;
	public static final int INDEX_TERM_INTERVAL_DEFAULT = IndexWriter.DEFAULT_TERM_INDEX_INTERVAL;
	public static final int INDEX_MAX_FIELD_LENGTH_DEFAULT = 60000;
	public static final boolean INDEX_USE_COMPOUND_FILE_DEFAULT = true;
	public static final boolean INDEX_AUTO_COMMIT_DEFAULT = true;

	private Analyzer analyzer;

	private Similarity similarity;
	private int mergeFactor;
	private double ramBufferSize;
	private int termIndexInterval;
	private int maxFieldLength;
	private boolean useCompoundFile;
	private boolean autoCommit;

	public IndexWriterFactory() {
		this.mergeFactor = INDEX_MERGE_FACTOR_DEFAULT;
		this.ramBufferSize = INDEX_RAM_BUFFER_SIZE_DEFAULT;
		this.termIndexInterval = INDEX_TERM_INTERVAL_DEFAULT;
		this.maxFieldLength = INDEX_MAX_FIELD_LENGTH_DEFAULT;
		this.useCompoundFile = INDEX_USE_COMPOUND_FILE_DEFAULT;
		this.autoCommit = INDEX_AUTO_COMMIT_DEFAULT;
	}

	/**
	 * Set the default analyzer to use in IndexWriters created by this factory.
	 */
	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	/**
	 * Set the value of auto-commit to use in IndexWriters created by this
	 * factory.
	 */
	public void setAutoCommit(boolean autoCommit) {
		this.autoCommit = autoCommit;
	}

	/**
	 * Set the value of maxFieldLength to use in IndexWriters created by this
	 * factory.
	 */
	public void setMaxFieldLength(int fieldLength) {
		this.maxFieldLength = fieldLength;
	}

	/**
	 * Set the value of mergeFactor to use in IndexWriters created by this
	 * factory.
	 */
	public void setMergeFactor(int factor) {
		this.mergeFactor = factor;
	}

	/**
	 * Set the value of RAMBufferSizeMB to use in IndexWriters created by this
	 * factory.
	 */
	public void setRamBufferSizeMB(double mb) {
		this.ramBufferSize = mb;
	}

	/**
	 * Set the Similarity implementation to use in IndexWriters created by this
	 * factory.
	 */
	public void setSimilarity(Similarity similarity) {
		this.similarity = similarity;
	}

	/**
	 * Set the termIndexInterval to use in IndexWriters created by this factory.
	 */
	public void setTermIndexInterval(int termIndexInterval) {
		this.termIndexInterval = termIndexInterval;
	}

	/**
	 * Set the value of useCompoundFile to use in IndexWriters created by this
	 * factory.
	 */
	public void setUseCompoundFile(boolean useCompoundFile) {
		this.useCompoundFile = useCompoundFile;
	}

	/**
	 * Create an IndexWriter for a new index at the given path.
	 * <p>
	 * This creates a new, empty index. If there is an existing index at the
	 * given location, it will be replaced by the new one. So take care!
	 * 
	 * @param path
	 *            where to create the new index
	 * @return the IndexWriter for the new index
	 * @throws IOException
	 *             if there is a problem creating the index
	 */
	public IndexWriter getIndexWriter(String path) throws IOException {
		return getIndexWriter(path, true);
	}

	/**
	 * Create or open an IndexWriter for an index at the given path.
	 * 
	 * @param path
	 *            location of the index
	 * @param create
	 *            true to create a new index, false to open existing index
	 * @return an IndexWriter
	 * @throws IOException
	 *             if there is a problem creating or opening the index
	 */
	public IndexWriter getIndexWriter(String path, boolean create)
			throws IOException {
		return getIndexWriter(FSDirectory.getDirectory(path), create);
	}

	/**
	 * Create an IndexWriter for a new index in the given Directory.
	 * <p>
	 * This creates a new, empty index. If there is an existing index at the
	 * given location, it will be replaced by the new one. So take care!
	 * 
	 * @param path
	 *            where to create the new index
	 * @return the IndexWriter for the new index
	 * @throws IOException
	 *             if there is a problem creating the index
	 */
	public IndexWriter getIndexWriter(Directory path) throws IOException {
		return getIndexWriter(path, true);
	}

	/**
	 * Create or open an IndexWriter for an index in the given Directory.
	 * 
	 * @param path
	 *            location of the index
	 * @param create
	 *            true to create a new index, false to open existing index
	 * @return an IndexWriter
	 * @throws IOException
	 *             if there is a problem creating or opening the index
	 */
	@SuppressWarnings("deprecation")
	public IndexWriter getIndexWriter(Directory path, boolean create)
			throws IOException {
		IndexWriter writer = new IndexWriter(path, autoCommit, analyzer, create);
		configureWriter(writer);
		return writer;
	}

	/**
	 * Apply the configuration of this factory to an IndexWriter.
	 * 
	 * @param writer
	 *            the IndexWriter to configure
	 */
	private void configureWriter(IndexWriter writer) {
		if (similarity != null) {
			writer.setSimilarity(similarity);
		}
		writer.setMergeFactor(mergeFactor);
		writer.setRAMBufferSizeMB(ramBufferSize);
		writer.setTermIndexInterval(termIndexInterval);
		writer.setMaxFieldLength(maxFieldLength);
		writer.setUseCompoundFile(useCompoundFile);
	}
}
